package com.wangbo.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

public class Client {
    public static void main(String[] args) {
        // 创建一个 ThreadLocal 对象
        ThreadLocal<String> threadLocal = new ThreadLocal<>();
        // 线程池处理任务
        ExecutorService threadPool = Executors.newFixedThreadPool(2);

        // 测试 ThreadLocal 基本使用
//        test01(threadLocal, threadPool);

        // 测试 threadLocal.initialValue() 设置默认值
//        test02(threadPool);

        // 测试 ThreadLocal.withInitial() 设置默认值
        test03(threadPool);
    }

    /**
     * ThreadLocal 基础使用
     * set： ThreadLocalMap
     * get: ThreadLocalMap中有值，直接返回；ThreadLocalMap中没有值，调用初始化方法，返回默认值
     * remove: 删除线程变量
     */
    public static void test01(ThreadLocal<String> threadLocal, ExecutorService threadPool) {
        // 定义任务
        Runnable task = new Runnable() {
            @Override
            public void run() {
                // 设置线程私有变量
                threadLocal.set(Thread.currentThread().getName()+"的线程私有变量");
                try {
                    // 模拟工作
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                try {
                    // 标识当前线程
                    String tName = Thread.currentThread().getName();
                    // 获取线程私有变量
                    String value = threadLocal.get();
                    // 打印线程及其私有变量
                    System.out.printf("%s 得到值：%s%n", tName, value);
                } finally {
                    // 私有变量用完删除，防止内存溢出
                    threadLocal.remove();
                }
            }
        };

        // 线程池执行任务
        threadPool.submit(task);
        threadPool.submit(task);
        // 线程池用完关闭，自动回收
        threadPool.shutdown();
    }

    /**
     * ThreadLocal 高级用法1
     * initialValue(): 设置默认值
     */
    public static void test02(ExecutorService threadPool) {
        ThreadLocal<String> threadLocal = new ThreadLocal<String>() {
            @Override
            protected String initialValue() {
                System.out.println("执行 initialValue() 方法");
                return "默认值";
            }
        };

        // 定义任务
        Runnable task = new Runnable() {
            @Override
            public void run() {
                try {
                    // 模拟工作
                    Thread.sleep(1200L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                try {
                    // 标识当前线程
                    String tName = Thread.currentThread().getName();
                    // 获取当前线程私有变量
                    String value = threadLocal.get();
                    // 打印线程及其私有变量
                    System.out.printf("%s 得到：%s%n", tName, value);
                } finally {
                    // 私有变量用完删除，防止内存溢出
                    threadLocal.remove();
                }
            }
        };

        threadPool.submit(task);
        threadPool.submit(task);
        threadPool.shutdown();
    }


    /**
     * ThreadLocal 高级使用2
     * withInitial(): 设置默认值
     */
    public static void test03(ExecutorService threadPool) {
        ThreadLocal<String> threadLocal = ThreadLocal.withInitial(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println("执行 withInitial() 方法");
                return "默认值";
            }
        });

        Runnable task = new Runnable() {
            @Override
            public void run() {
                try {
                    // 模拟工作
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                try {
                    // 标识当前线程
                    String tName = Thread.currentThread().getName();
                    // 获取当前线程私有变量
                    String value = threadLocal.get();
                    // 打印线程及其私有变量
                    System.out.printf("%s 得到：%s%n", tName, value);
                } finally {
                    // 私有变量用完删除，防止内存溢出
                    threadLocal.remove();
                }
            }
        };

        threadPool.submit(task);
        threadPool.submit(task);
        threadPool.shutdown();
    }
}
